package com.css.security.browser.session;

import com.css.common.core.constent.CommonConstant;
import com.css.common.core.utils.R;
import com.css.common.security.constant.SecurityConstants;
import com.css.common.security.properties.SecurityProperties;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.util.UrlUtils;
import org.springframework.util.Assert;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * AbstractSessionStrategy
 * 抽象的session失效处理器
 *
 * @author hanyx
 * @date 2019/04/15
 */
@Slf4j
public class AbstractSessionStrategy {

    /**
     * 跳转的url
     */
    private String destinationUrl;
    /**
     * 系统配置信息
     */
    private SecurityProperties securityPropertie;
    /**
     * 重定向策略
     */
    private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
    /**
     * 跳转前是否创建新的session
     */
    private boolean createNewSession = true;

    private ObjectMapper objectMapper = new ObjectMapper();

    public AbstractSessionStrategy(SecurityProperties securityPropertie) {
        String invalidSessionUrl = securityPropertie.getBrowser().getSession().getSessionInvalidUrl();
        Assert.isTrue(UrlUtils.isValidRedirectUrl(invalidSessionUrl), "url must start with '/' or with 'http(s)'");
        Assert.isTrue(StringUtils.endsWithIgnoreCase(invalidSessionUrl, SecurityConstants.HTML_SUFFIX), "url must end with '.html'");
        this.destinationUrl = invalidSessionUrl;
        this.securityPropertie = securityPropertie;
    }

    protected void onSessionInvalid(HttpServletRequest request, HttpServletResponse response) throws IOException {

        log.info("session失效");

        if (createNewSession) {
            request.getSession();
        }
        // 当session失效时 直接跳转到登录页面 开关
        if (securityPropertie.getBrowser().getSession().isRedirectFlag()) {
            redirectStrategy.sendRedirect(request, response, securityPropertie.getBrowser().getSignInPage());
        } else {
            String sourceUrl = request.getRequestURI();
            String targetUrl;
            if (StringUtils.endsWithIgnoreCase(sourceUrl, SecurityConstants.HTML_SUFFIX)) {

                /**
                 * 当请求路径不是登录页和登出页时 跳转到默认session失效页面
                 */
                if (StringUtils.equals(sourceUrl, securityPropertie.getBrowser().getSignInPage())
                        || StringUtils.equals(sourceUrl, securityPropertie.getBrowser().getSignOutUrl())) {
                    targetUrl = sourceUrl;
                } else {
                    targetUrl = destinationUrl;
                }
                log.info("跳转到:" + targetUrl);
                redirectStrategy.sendRedirect(request, response, targetUrl);
            } else {
                Object result = buildResponseContent(request);
                response.setStatus(HttpStatus.UNAUTHORIZED.value());
                response.setContentType(SecurityConstants.APPLICATION_JSON_CONTENT_TYPE);
                response.getWriter().write(objectMapper.writeValueAsString(result));
            }
        }
    }

    protected Object buildResponseContent(HttpServletRequest request) {
        String message = "session已失效";
        if (isConcurrency()) {
            message = message + "，有可能是并发登录导致的";
        }
        return R.builder().code(CommonConstant.SESSION_FAIL).msg(message).data(Boolean.FALSE).build();
    }

    /**
     * session失效是否是并发导致的
     *
     * @return
     */
    protected boolean isConcurrency() {
        return false;
    }

    public void setCreateNewSession(boolean createNewSession) {
        this.createNewSession = createNewSession;
    }
}
